#ifndef JDATASTREAM_H
#define JDATASTREAM_H

#include <JXQCore/JXQGlobal>
#include <JXQCore/JString>
#include <list>

namespace JXQ
{

class JAbstractIO;
class JDataStreamPrivate;

class JXQLIB_EXPORT JDataStream
{
public:
	typedef std::list<uint64_t>  Buffer;
	explicit JDataStream(Buffer &buffer);

	explicit JDataStream(JAbstractIO *io = nullptr);

	JDataStream(const JDataStream &other);
	JDataStream(JDataStream &&other);

	~JDataStream();

public:
	const JDataStream &operator=(const JDataStream &other);
	const JDataStream &operator=(JDataStream &&other);

public:
	JDataStream &operator<<(signed char);
	JDataStream &operator<<(unsigned char);
	JDataStream &operator<<(short);
	JDataStream &operator<<(unsigned short);
	JDataStream &operator<<(int);
	JDataStream &operator<<(unsigned int);
	JDataStream &operator<<(long);
	JDataStream &operator<<(unsigned long);
	JDataStream &operator<<(long long);
	JDataStream &operator<<(unsigned long long);
	JDataStream &operator<<(float);
	JDataStream &operator<<(double);
	JDataStream &operator<<(long double);
	JDataStream &operator<<(char *str);
	JDataStream &operator<<(const char *str);
	inline JDataStream &operator<<(short*);
	inline JDataStream &operator<<(unsigned short*);
	inline JDataStream &operator<<(int*);
	inline JDataStream &operator<<(unsigned int*);
	inline JDataStream &operator<<(long*);
	inline JDataStream &operator<<(unsigned long*);
	inline JDataStream &operator<<(long long*);
	inline JDataStream &operator<<(unsigned long long*);
	inline JDataStream &operator<<(float*);
	inline JDataStream &operator<<(double*);
	inline JDataStream &operator<<(long double*);
	inline JDataStream &operator<<(const JString &str);

public:
	JDataStream &operator>>(signed char&);
	JDataStream &operator>>(unsigned char&);
	JDataStream &operator>>(short&);
	JDataStream &operator>>(unsigned short&);
	JDataStream &operator>>(int&);
	JDataStream &operator>>(unsigned int&);
	JDataStream &operator>>(long&);
	JDataStream &operator>>(unsigned long&);
	JDataStream &operator>>(long long&);
	JDataStream &operator>>(unsigned long long&);
	JDataStream &operator>>(float&);
	JDataStream &operator>>(double&);
	JDataStream &operator>>(long double&);
	JDataStream &operator>>(char *str);
	inline JDataStream &operator>>(short*);
	inline JDataStream &operator>>(unsigned short*);
	inline JDataStream &operator>>(int*);
	inline JDataStream &operator>>(unsigned int*);
	inline JDataStream &operator>>(long*);
	inline JDataStream &operator>>(unsigned long*);
	inline JDataStream &operator>>(long long*);
	inline JDataStream &operator>>(unsigned long long*);
	inline JDataStream &operator>>(float*);
	inline JDataStream &operator>>(double*);
	inline JDataStream &operator>>(long double*);
	inline JDataStream &operator>>(JString &str);

private:
	JDataStreamPrivate *d_ptr;
};

inline JDataStream &JDataStream::operator<<(short *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(unsigned short *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(int *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(unsigned int *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(long *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(unsigned long *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(long long *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(unsigned long long *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(float *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(double *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(long double *data)
{
	if( data != nullptr )
		return operator<<(*data);
	return *this;
}

inline JDataStream &JDataStream::operator<<(const JString &data)
{
	return operator<<(data.c_str());
}

inline JDataStream &JDataStream::operator>>(short *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(unsigned short *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(int *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(unsigned int *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(long *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(unsigned long *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(long long *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(unsigned long long *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(float *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(double *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(long double *data)
{
	if( data != nullptr )
		return operator>>(*data);
	return *this;
}

inline JDataStream &JDataStream::operator>>(JString &data)
{
	auto tmp = std::shared_ptr<char>(new char[data.size() + 1]);
	operator>>(tmp.get());
	data = tmp.get();
	return *this;
}

} // namespace JXQ


#endif //JDATASTREAM_H
